package com.dingding.commonservice.core.distance.service.impl;

import java.math.BigDecimal;
import java.util.Date;

import org.springframework.stereotype.Component;

import com.dingding.common.core.util.DateFormatUtil;
import com.dingding.common.core.util.ToolUtil;
import com.dingding.commonservice.core.distance.service.ICalculateDistanceService;
import com.dingding.facade.commonservice.common.dto.distance.ReqMileageCostDTO;
import com.dingding.facade.commonservice.common.dto.distance.ResMileageCostDTO;

/**
 * 
 * @ClassName: CalculateDistanceServiceImpl 
 * @Description: 计算距离价格业务逻辑实现类
 * @author YHQ
 * @date 2016年12月2日 上午11:43:30
 * @since V2.5.7
 * 
 */
@Component("calculateDistanceService")
public class CalculateDistanceServiceImpl implements ICalculateDistanceService{

	/**
	 * 
	 * @Title: calculationMileageCost 
	 * @Description: 计算里程费用 (专车、出租车使用)
	 * @param reqMileageCostDTO 
	 * @author YHQ 
	 * @since V2.5.7
	 * @return ResMileageCostDTO    返回类型
	 * 
	 */
	@Override
	public ResMileageCostDTO calculationMileageCost(ReqMileageCostDTO reqMileageCostDTO) {
		
		// 判断客户端请求参数是否为空
		if(reqMileageCostDTO == null || !ToolUtil.validateParam(reqMileageCostDTO)){
			return null;
		}
		
		ResMileageCostDTO resMileageCostDTO = new ResMileageCostDTO();
		
		// 里程费用
		BigDecimal totalMoney = new BigDecimal(0.0);
		
		// 计算里程费用
		totalMoney = this.distanceCost(reqMileageCostDTO);
		// 夜间行车费用
		totalMoney = totalMoney.add(this.nightDrivingCost(reqMileageCostDTO));
		// 长途费用
		totalMoney = totalMoney.add(this.longDistanceCost(reqMileageCostDTO));
		// 时长费 
		totalMoney = totalMoney.add(durationCost(reqMileageCostDTO));
		// 最低消费
		totalMoney = this.minimumConsumption(totalMoney, reqMileageCostDTO);
		
		resMileageCostDTO.setTotalMoney(totalMoney);
		
		return resMileageCostDTO;
	}
	
	/**
	 * 
	 * @Title: distanceCost 
	 * @Description: 计算里程费用 
	 * @param totalMoney 订单里程总费用
	 * @param reqMileageCostDTO 客户端请求参数
	 * @author YHQ 
	 * @since V2.5.7
	 * @return void    返回类型
	 * 
	 */
	public BigDecimal distanceCost(ReqMileageCostDTO reqMileageCostDTO){
		
		// 订单里程
		BigDecimal orderMileage = reqMileageCostDTO.getOrderMileage();
		// 里程费
		BigDecimal mileageFee = reqMileageCostDTO.getChargeRule().getMileageFee();
		
		// 计算订单里程费用
		return orderMileage.multiply(mileageFee); 
	}
	
	/**
	 * 
	 * @Title: nightDrivingCost 
	 * @Description: 夜间行驶费用计算 
	 * @param reqMileageCostDTO 客户端请求参数
	 * @author YHQ 
	 * @since V2.5.7
	 * @return BigDecimal    返回类型
	 * 
	 */
	public BigDecimal nightDrivingCost(ReqMileageCostDTO reqMileageCostDTO){
		
		// 如果夜间行驶距离不为空，则进行计算
		if(reqMileageCostDTO.getNightMileage() != null){
			
			// 夜间行驶距离        
			BigDecimal nightMileage = reqMileageCostDTO.getNightMileage();
			// 夜间行车费
			BigDecimal nightFee = reqMileageCostDTO.getChargeRule().getNightFee();
			 
			return nightMileage.multiply(nightFee);
		}
		
		return new BigDecimal(0);
	}
	
	/**
	 * 
	 * @Title: nightDrivingByFirst 
	 * @Description: 总时长一天内完成 
	 * @param startTime 出发时间
	 * @param endTime	确认到达时间
	 * @param nightStart	夜间行车开始时间
	 * @param nightEnd		夜间行车结束时间
	 * @author YHQ 
	 * @return BigDecimal    返回类型
	 * 
	 */
	public BigDecimal nightDrivingByFirst(Date startTime,Date endTime,Date nightStart,Date nightEnd){
		
		// TODO 夜间行车开始时间为当天的开始时间，夜间行车的结束时间为当天的24:00
		
		BigDecimal duration = new BigDecimal(0.0);
		
		// 比较出发时间与夜间开始时间   1:出发时间大于夜间开始时间   0:出发时间等于夜间开始时间   -1:出发时间小于夜间开始时间
		int compareFirst = DateFormatUtil.compareDate(startTime, nightStart); 
		// 比较确认到达时间与夜间结束时间   1:确认到达时间大于夜间结束时间   0:确认到达时间等于夜间结束时间   -1:确认到达时间小于夜间结束时间
		int compareSecond = DateFormatUtil.compareDate(endTime, nightEnd);
		// 比较出发时间与夜间结束时间   1:出发时间大于夜间结束时间   0:出发时间等于夜间结束时间   -1:出发时间小于夜间结束时间
		int compareThird = DateFormatUtil.compareDate(startTime, nightEnd);
		// 比较确认到达时间与夜间开始时间   1:确认到达时间大于夜间开始时间   0:确认到达时间等于夜间开始时间   -1:确认到达时间小于夜间开始时间
		int compareFourth = DateFormatUtil.compareDate(endTime, nightStart);
		
		// 全部属于夜间行车
		if(compareFirst > 0 && compareSecond < 0){
			
			// 行驶时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(startTime, endTime);
			
			duration.add(new BigDecimal(oneDuration));
		}
		
		// 出发时白天,确认到达时夜间
		if(compareFirst < 0 && compareThird > 0 && compareFourth > 0 && compareSecond < 0 ){
			
			// 行驶时长
			int twoDuration = DateFormatUtil.getDateTimeDifferenceBySecond(nightStart, endTime);
			
			duration.add(new BigDecimal(twoDuration));
		}
		
		// 出发时夜间,确认到达时白天
		if(compareThird < 0 && compareSecond >= 0 && compareFourth < 0){
			
			// 行驶时长
			int threeDuration = DateFormatUtil.getDateTimeDifferenceBySecond(startTime, endTime);
			
			duration.add(new BigDecimal(threeDuration));
		}else if(compareThird < 0 && compareSecond < 0 && compareFourth > 0){
			
			// 凌晨夜间行驶时长
			int fourDuration = DateFormatUtil.getDateTimeDifferenceBySecond(startTime, nightEnd);
			// 晚上夜间行驶实在
			int fiveDuration = DateFormatUtil.getDateTimeDifferenceBySecond(nightStart, endTime);
						
			duration.add(new BigDecimal(fourDuration + fiveDuration));
		}
		
		return duration;
	}
	
	/**
	 * 
	 * @Title: nightDrivingBySecond 
	 * @Description: 跨天的夜间行驶时长
	 * @param startTime 		出发时间
	 * @param endTime			确认到达时间
	 * @param currentNightStart	当天的夜间行驶开始时间
	 * @param currentNightEnd	当天的夜间行驶结束时间
	 * @param afterNightStart	第二天的夜间行驶开始时间
	 * @param afterNightEnd		第二天的夜间行驶结束时间
	 * @author YHQ 
	 * @return BigDecimal    返回类型
	 * 
	 */
	public BigDecimal nightDrivingBySecond(Date startTime,Date endTime,Date currentNightStart,Date currentNightEnd,Date afterNightStart,Date afterNightEnd){
		
		BigDecimal duration = new BigDecimal(0.0);
		
		// 比较出发时间与当天夜间开始时间   1:出发时间大于当天夜间开始时间   0:出发时间等于当天夜间开始时间   -1:出发时间小于当天夜间开始时间
		int compareFirst = DateFormatUtil.compareDate(startTime, currentNightStart); 
		// 比较出发时间与当天夜间结束时间   1:出发时间大于当前夜间结束时间   0:出发时间等于当前夜间结束时间   -1:出发时间小于当前夜间结束时间
		int compareSecond = DateFormatUtil.compareDate(startTime, currentNightEnd);
		// 比较确认到达时间与第二天夜间开始时间   1:确认到达时间大于第二天夜间开始时间   0:确认到达时间等于第二天夜间开始时间   -1:确认到达时间小于第二天夜间开始时间
		int compareThird = DateFormatUtil.compareDate(endTime, afterNightStart);
		// 比较确认到达时间与夜间结束时间   1:确认到达时间大于夜间结束时间   0:确认到达时间等于夜间结束时间   -1:确认到达时间小于夜间结束时间
		int compareFourth = DateFormatUtil.compareDate(endTime, afterNightEnd);
		
		// 黑 - 白 - 黑 - 黑 - 白 - 黑
		if(compareSecond < 0 && compareThird > 0 ){
			
			// 当天凌晨夜间行驶时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(startTime, currentNightEnd);
			// 当天晚上夜间行车时长已经第二天凌晨行车时长
			int twoDuration = DateFormatUtil.getDateTimeDifferenceBySecond(currentNightStart, afterNightEnd);
			// 第二天晚上行车时长
			int threeDuration = DateFormatUtil.getDateTimeDifferenceBySecond(afterNightStart, endTime);
			
			duration.add(new BigDecimal(oneDuration + twoDuration + threeDuration));
		}
		
		// 黑 - 黑 - 白 - 黑
		if(compareFirst > 0 && compareThird > 0){
			
			// 当天晚上夜间行车时长已经第二天凌晨行车时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(currentNightStart, afterNightEnd);
			// 第二天晚上行车时长
			int threeDuration = DateFormatUtil.getDateTimeDifferenceBySecond(afterNightStart, endTime);
			
			duration.add(new BigDecimal(oneDuration + threeDuration));
		}
		
		// 黑 - 白 - 黑 - 黑
		
		if(compareSecond < 0 && compareFourth <= 0){
			
			// 当天凌晨夜间行驶时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(startTime, currentNightEnd);
			// 当天晚上夜间行车时长已经第二天凌晨行车时长
			int twoDuration = DateFormatUtil.getDateTimeDifferenceBySecond(currentNightStart, endTime);
			
			duration.add(new BigDecimal(oneDuration + twoDuration));
		}
		
		// 黑 - 黑
		if(compareFirst > 0 && compareFourth < 0){
			
			// 当天晚上夜间行车时长已经第二天凌晨行车时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(currentNightStart, endTime);
			
			duration.add(new BigDecimal(oneDuration));
		}
		
		// 白 - 黑 - 黑 - 白 - 黑
		if(compareSecond > 0 && compareThird > 0){
			
			// 当天晚上夜间行车时长已经第二天凌晨行车时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(currentNightStart, afterNightEnd);
			// 第二天晚上行车时长
			int twoDuration = DateFormatUtil.getDateTimeDifferenceBySecond(afterNightStart, endTime);
			
			duration.add(new BigDecimal(oneDuration + twoDuration));
			
		}
		
		// 白 - 黑 - 黑
		if(compareSecond > 0 && compareFourth <= 0){
			
			// 当天晚上夜间行车时长已经第二天凌晨行车时长
			int oneDuration = DateFormatUtil.getDateTimeDifferenceBySecond(currentNightStart, endTime);
			
			duration.add(new BigDecimal(oneDuration));
		}
		
		return null;
	}
	
	/**
	 * 
	 * @Title: longDistanceCost 
	 * @Description: 长途费用 
	 * @param totalMoney 确认上车时间
	 * @param reqMileageCostDTO 客户端请求参数
	 * @author YHQ 
	 * @since V2.5.7
	 * @return void    返回类型
	 */
	public BigDecimal longDistanceCost(ReqMileageCostDTO reqMileageCostDTO){
		
		// 订单里程
		BigDecimal orderMileage = reqMileageCostDTO.getOrderMileage();
		// 长途起始里程
		BigDecimal longStartMileage = reqMileageCostDTO.getChargeRule().getLongStartMileage();
		// 长途费用
		BigDecimal longFee = reqMileageCostDTO.getChargeRule().getLongFee();
		
		// 计算长途部分的距离
		BigDecimal longDistance = orderMileage.subtract(longStartMileage);
		
		if(orderMileage.compareTo(longStartMileage) > 0){
			return longDistance.multiply(longFee); 
		}
		
		return new BigDecimal(0);
	}
	
	/**
	 * 
	 * @Title: durationCost 
	 * @Description: 时长费 
	 * @param reqMileageCostDTO 客户端请求参数
	 * @author YHQ 
	 * @return BigDecimal    返回类型
	 * 
	 */
	public BigDecimal durationCost(ReqMileageCostDTO reqMileageCostDTO){
		
		// 时长费
		BigDecimal durationFee = reqMileageCostDTO.getChargeRule().getDurationFee();
		// 时长
		BigDecimal duraton = reqMileageCostDTO.getDuration();
		
		return durationFee.multiply(duraton);
	}
	
	/**
	 * 
	 * @Title: minimumConsumption 
	 * @Description: 最低消费 
	 * @param totalMoney 里程费用
	 * @param reqMileageCostDTO 客户端请求参数
	 * @author YHQ 
	 * @return void    返回类型
	 */
	public BigDecimal minimumConsumption(BigDecimal totalMoney,ReqMileageCostDTO reqMileageCostDTO){
		
		// 最低消费
		BigDecimal minimums = reqMileageCostDTO.getChargeRule().getMinimums();
		
		// 判断里程费用大于最低消费
		if(reqMileageCostDTO.getCalculationType() != 2 && totalMoney.compareTo(minimums) < 0){
			return minimums;
		}
		
		return totalMoney;
	}
	
	/**
	 * 
	 * @Title: getNightTime 
	 * @Description: 获取夜间行车时间
	 * @param date 提供日期
	 * @param time 提供时间
	 * @author YHQ 
	 * @return Date    返回类型
	 */
	public Date getNightTime(Date date,Date time){
		
		return DateFormatUtil.yyyy_MM_dd_HHmmss(DateFormatUtil.yyyy_MM_dd(date) + " " + DateFormatUtil.HHmmSS(time));
	}
	
}
